home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / BasicHLSL / BasicHLSL.cpp next >
Encoding:
C/C++ Source or Header  |  2004-09-28  |  32.2 KB  |  703 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: BasicHLSL.cpp
  3. //
  4. // This sample shows a simple example of the Microsoft Direct3D's High-Level 
  5. // Shader Language (HLSL) using the Effect interface. 
  6. //
  7. // Copyright (c) Microsoft Corporation. All rights reserved.
  8. //--------------------------------------------------------------------------------------
  9. #include "dxstdafx.h"
  10. #include "resource.h"
  11.  
  12. //#define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  13. //#define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  14.  
  15.  
  16. //--------------------------------------------------------------------------------------
  17. // Global variables
  18. //--------------------------------------------------------------------------------------
  19. ID3DXFont*              g_pFont = NULL;         // Font for drawing text
  20. ID3DXSprite*            g_pSprite = NULL;       // Sprite for batching draw text calls
  21. bool                    g_bShowHelp = true;     // If true, it renders the UI control text
  22. CModelViewerCamera      g_Camera;               // A model viewing camera
  23. ID3DXEffect*            g_pEffect = NULL;       // D3DX effect interface
  24. ID3DXMesh*              g_pMesh = NULL;         // Mesh object
  25. ID3DXMesh*              g_pArrowMesh = NULL;    // Mesh object
  26. IDirect3DTexture9*      g_pMeshTexture = NULL;  // Mesh texture
  27. CDXUTDialog             g_HUD;                  // manages the 3D UI
  28. CDXUTDialog             g_SampleUI;             // dialog for sample specific controls
  29. bool                    g_bEnablePreshader;     // if TRUE, then D3DXSHADER_NO_PRESHADER is used when compiling the shader
  30. D3DXMATRIXA16           g_mWorldFix;
  31.  
  32. #define MAX_LIGHTS 3
  33. CDXUTDirectionWidget g_LightControl[MAX_LIGHTS];
  34. float                g_fLightScale;
  35. int                  g_nNumActiveLights;
  36. int                  g_nActiveLight;
  37.  
  38.  
  39. //--------------------------------------------------------------------------------------
  40. // UI control IDs
  41. //--------------------------------------------------------------------------------------
  42. #define IDC_TOGGLEFULLSCREEN    1
  43. #define IDC_TOGGLEREF           3
  44. #define IDC_CHANGEDEVICE        4
  45. #define IDC_ENABLE_PRESHADER    5
  46. #define IDC_NUM_LIGHTS          6
  47. #define IDC_NUM_LIGHTS_STATIC   7
  48. #define IDC_ACTIVE_LIGHT        8
  49. #define IDC_LIGHT_SCALE         9
  50. #define IDC_LIGHT_SCALE_STATIC  10
  51.  
  52.  
  53. //--------------------------------------------------------------------------------------
  54. // Forward declarations 
  55. //--------------------------------------------------------------------------------------
  56. bool    CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed );
  57. void    CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps );
  58. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  59. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  60. void    CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  61. void    CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  62. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing );
  63. void    CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown  );
  64. void    CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl );
  65. void    CALLBACK OnLostDevice();
  66. void    CALLBACK OnDestroyDevice();
  67.  
  68. void    InitApp();
  69. HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh );
  70. void    RenderText( double fTime );
  71. HRESULT RenderLightArrow( D3DXVECTOR3 lightDir, D3DXCOLOR arrowColor );
  72.  
  73. //--------------------------------------------------------------------------------------
  74. // Entry point to the program. Initializes everything and goes into a message processing 
  75. // loop. Idle time is used to render the scene.
  76. //--------------------------------------------------------------------------------------
  77. INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
  78. {
  79.     // Set the callback functions. These functions allow the sample framework to notify
  80.     // the application about device changes, user input, and windows messages.  The 
  81.     // callbacks are optional so you need only set callbacks for events you're interested 
  82.     // in. However, if you don't handle the device reset/lost callbacks then the sample 
  83.     // framework won't be able to reset your device since the application must first 
  84.     // release all device resources before resetting.  Likewise, if you don't handle the 
  85.     // device created/destroyed callbacks then the sample framework won't be able to 
  86.     // recreate your device resources.
  87.     DXUTSetCallbackDeviceCreated( OnCreateDevice );
  88.     DXUTSetCallbackDeviceReset( OnResetDevice );
  89.     DXUTSetCallbackDeviceLost( OnLostDevice );
  90.     DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
  91.     DXUTSetCallbackMsgProc( MsgProc );
  92.     DXUTSetCallbackKeyboard( KeyboardProc );
  93.     DXUTSetCallbackFrameRender( OnFrameRender );
  94.     DXUTSetCallbackFrameMove( OnFrameMove );
  95.  
  96.     // Show the cursor and clip it when in full screen
  97.     DXUTSetCursorSettings( true, true );
  98.  
  99.     InitApp();
  100.  
  101.     // Initialize the sample framework and create the desired Win32 window and Direct3D 
  102.     // device for the application. Calling each of these functions is optional, but they
  103.     // allow you to set several options which control the behavior of the framework.
  104.     DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  105.     DXUTCreateWindow( L"BasicHLSL" );
  106.     DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );
  107.  
  108.     // Pass control to the sample framework for handling the message pump and 
  109.     // dispatching render calls. The sample framework will call your FrameMove 
  110.     // and FrameRender callback when there is idle time between handling window messages.
  111.     DXUTMainLoop();
  112.  
  113.     // Perform any application-level cleanup here. Direct3D device resources are released within the
  114.     // appropriate callback functions and therefore don't require any cleanup code here.
  115.  
  116.     return DXUTGetExitCode();
  117. }
  118.  
  119.  
  120. //--------------------------------------------------------------------------------------
  121. // Initialize the app 
  122. //--------------------------------------------------------------------------------------
  123. void InitApp()
  124. {
  125.     g_bEnablePreshader = true;
  126.  
  127.     for( int i=0; i<MAX_LIGHTS; i++ )
  128.         g_LightControl[i].SetLightDirection( D3DXVECTOR3( sinf(D3DX_PI*2*i/MAX_LIGHTS-D3DX_PI/6), 0, -cosf(D3DX_PI*2*i/MAX_LIGHTS-D3DX_PI/6) ) );
  129.  
  130.     g_nActiveLight = 0;
  131.     g_nNumActiveLights = 1;
  132.     g_fLightScale = 1.0f;
  133.  
  134.     // Initialize dialogs
  135.     g_HUD.SetCallback( OnGUIEvent ); int iY = 10; 
  136.     g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
  137.     g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
  138.     g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22 );
  139.  
  140.     g_SampleUI.SetCallback( OnGUIEvent ); iY = 10; 
  141.  
  142.     WCHAR sz[100];
  143.     iY += 24;
  144.     _snwprintf( sz, 100, L"# Lights: %d", g_nNumActiveLights ); sz[99] = 0;
  145.     g_SampleUI.AddStatic( IDC_NUM_LIGHTS_STATIC, sz, 35, iY += 24, 125, 22 );
  146.     g_SampleUI.AddSlider( IDC_NUM_LIGHTS, 50, iY += 24, 100, 22, 1, MAX_LIGHTS, g_nNumActiveLights );
  147.  
  148.     iY += 24;
  149.     _snwprintf( sz, 100, L"Light scale: %0.2f", g_fLightScale ); sz[99] = 0;
  150.     g_SampleUI.AddStatic( IDC_LIGHT_SCALE_STATIC, sz, 35, iY += 24, 125, 22 );
  151.     g_SampleUI.AddSlider( IDC_LIGHT_SCALE, 50, iY += 24, 100, 22, 0, 20, (int) (g_fLightScale * 10.0f) );
  152.  
  153.     iY += 24;
  154.     g_SampleUI.AddButton( IDC_ACTIVE_LIGHT, L"Change active light (K)", 35, iY += 24, 125, 22, 'K' );
  155.     g_SampleUI.AddCheckBox( IDC_ENABLE_PRESHADER, L"Enable preshaders", 35, iY += 24, 125, 22, g_bEnablePreshader );
  156. }
  157.  
  158.  
  159. //--------------------------------------------------------------------------------------
  160. // Called during device initialization, this code checks the device for some 
  161. // minimum set of capabilities, and rejects those that don't pass by returning E_FAIL.
  162. //--------------------------------------------------------------------------------------
  163. bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, 
  164.                                   D3DFORMAT BackBufferFormat, bool bWindowed )
  165. {
  166.     // No fallback defined by this app, so reject any device that 
  167.     // doesn't support at least ps1.1
  168.     if( pCaps->PixelShaderVersion < D3DPS_VERSION(1,1) )
  169.         return false;
  170.  
  171.     // Skip backbuffer formats that don't support alpha blending
  172.     IDirect3D9* pD3D = DXUTGetD3DObject(); 
  173.     if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
  174.                     AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, 
  175.                     D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
  176.         return false;
  177.  
  178.     return true;
  179. }
  180.  
  181.  
  182. //--------------------------------------------------------------------------------------
  183. // This callback function is called immediately before a device is created to allow the 
  184. // application to modify the device settings. The supplied pDeviceSettings parameter 
  185. // contains the settings that the framework has selected for the new device, and the 
  186. // application can make any desired changes directly to this structure.  Note however that 
  187. // the sample framework will not correct invalid device settings so care must be taken 
  188. // to return valid device settings, otherwise IDirect3D9::CreateDevice() will fail.  
  189. //--------------------------------------------------------------------------------------
  190. void CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps )
  191. {
  192.     // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  193.     // then switch to SWVP.
  194.     if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
  195.          pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) )
  196.     {
  197.         pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  198.     }
  199.     else
  200.     {
  201.         pDeviceSettings->BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  202.     }
  203.  
  204.     // This application is designed to work on a pure device by not using 
  205.     // IDirect3D9::Get*() methods, so create a pure device if supported and using HWVP.
  206.     if ((pCaps->DevCaps & D3DDEVCAPS_PUREDEVICE) != 0 && 
  207.         (pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0 )
  208.         pDeviceSettings->BehaviorFlags |= D3DCREATE_PUREDEVICE;
  209.  
  210.     // Debugging vertex shaders requires either REF or software vertex processing 
  211.     // and debugging pixel shaders requires REF.  
  212. #ifdef DEBUG_VS
  213.     if( pDeviceSettings->DeviceType != D3DDEVTYPE_REF )
  214.     {
  215.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
  216.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;                            
  217.         pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  218.     }
  219. #endif
  220. #ifdef DEBUG_PS
  221.     pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
  222. #endif
  223. }
  224.  
  225.  
  226. //--------------------------------------------------------------------------------------
  227. // This callback function will be called immediately after the Direct3D device has been 
  228. // created, which will happen during application initialization and windowed/full screen 
  229. // toggles. This is the best location to create D3DPOOL_MANAGED resources since these 
  230. // resources need to be reloaded whenever the device is destroyed. Resources created  
  231. // here should be released in the OnDestroyDevice callback. 
  232. //--------------------------------------------------------------------------------------
  233. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  234. {
  235.     HRESULT hr;
  236.  
  237.     // Initialize the font
  238.     V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, 
  239.                               OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, 
  240.                               L"Arial", &g_pFont ) );
  241.  
  242.     // Load the mesh
  243.     V_RETURN( LoadMesh( pd3dDevice, L"tiny\\tiny.x", &g_pMesh ) );
  244.     V_RETURN( LoadMesh( pd3dDevice, L"UI\\arrow.x", &g_pArrowMesh ) );
  245.  
  246.     D3DXVECTOR3* pData; 
  247.     D3DXVECTOR3 vCenter;
  248.     FLOAT fObjectRadius;
  249.     V( g_pMesh->LockVertexBuffer( 0, (LPVOID*) &pData ) );
  250.     V( D3DXComputeBoundingSphere( pData, g_pMesh->GetNumVertices(), D3DXGetFVFVertexSize( g_pMesh->GetFVF() ), &vCenter, &fObjectRadius ) );
  251.     V( g_pMesh->UnlockVertexBuffer() );
  252.  
  253.     D3DXMatrixTranslation( &g_mWorldFix, -vCenter.x, -vCenter.y, -vCenter.z );
  254.     D3DXMATRIXA16 m;
  255.     D3DXMatrixRotationY( &m, D3DX_PI );
  256.     g_mWorldFix *= m;
  257.     D3DXMatrixRotationX( &m, D3DX_PI / 2.0f );
  258.     g_mWorldFix *= m;
  259.  
  260.     V_RETURN( CDXUTDirectionWidget::StaticOnCreateDevice( pd3dDevice ) );
  261.     for( int i=0; i<MAX_LIGHTS; i++ )
  262.         g_LightControl[i].SetRadius( fObjectRadius );
  263.  
  264.     // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  265.     // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  266.     // processing, and debugging pixel shaders requires REF.  The 
  267.     // D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug experience in the 
  268.     // shader debugger.  It enables source level debugging, prevents instruction 
  269.     // reordering, prevents dead code elimination, and forces the compiler to compile 
  270.     // against the next higher available software target, which ensures that the 
  271.     // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  272.     // flags will cause slower rendering since the shaders will be unoptimized and 
  273.     // forced into software.  See the DirectX documentation for more information about 
  274.     // using the shader debugger.
  275.     DWORD dwShaderFlags = 0;
  276.     #ifdef DEBUG_VS
  277.         dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
  278.     #endif
  279.     #ifdef DEBUG_PS
  280.         dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
  281.     #endif
  282.  
  283.     // Preshaders are parts of the shader that the effect system pulls out of the 
  284.     // shader and runs on the host CPU. They should be used if you are GPU limited. 
  285.     // The D3DXSHADER_NO_PRESHADER flag disables preshaders.
  286.     if( !g_bEnablePreshader )
  287.         dwShaderFlags |= D3DXSHADER_NO_PRESHADER;
  288.  
  289.     // Read the D3DX effect file
  290.     WCHAR str[MAX_PATH];
  291.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"BasicHLSL.fx" ) );
  292.  
  293.     // If this fails, there should be debug output as to 
  294.     // why the .fx file failed to compile
  295.     V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags, NULL, &g_pEffect, NULL ) );
  296.  
  297.     // Create the mesh texture from a file
  298.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"tiny\\tiny_skin.bmp" ) );
  299.  
  300.     V_RETURN( D3DXCreateTextureFromFileEx( pd3dDevice, str, D3DX_DEFAULT, D3DX_DEFAULT, 
  301.                                        D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, 
  302.                                        D3DX_DEFAULT, D3DX_DEFAULT, 0, 
  303.                                        NULL, NULL, &g_pMeshTexture ) );
  304.  
  305.     // Set effect variables as needed
  306.     D3DXCOLOR colorMtrlDiffuse(1.0f, 1.0f, 1.0f, 1.0f);
  307.     D3DXCOLOR colorMtrlAmbient(0.35f, 0.35f, 0.35f, 0);
  308.  
  309.     V_RETURN( g_pEffect->SetValue("g_MaterialAmbientColor", &colorMtrlAmbient, sizeof(D3DXCOLOR) ) );
  310.     V_RETURN( g_pEffect->SetValue("g_MaterialDiffuseColor", &colorMtrlDiffuse, sizeof(D3DXCOLOR) ) );    
  311.     V_RETURN( g_pEffect->SetTexture( "g_MeshTexture", g_pMeshTexture) );
  312.  
  313.     // Setup the camera's view parameters
  314.     D3DXVECTOR3 vecEye(0.0f, 0.0f, -15.0f);
  315.     D3DXVECTOR3 vecAt (0.0f, 0.0f, -0.0f);
  316.     g_Camera.SetViewParams( &vecEye, &vecAt );
  317.     g_Camera.SetRadius( fObjectRadius*3.0f, fObjectRadius*0.5f, fObjectRadius*10.0f );
  318.  
  319.     return S_OK;
  320. }
  321.  
  322. //--------------------------------------------------------------------------------------
  323. // This function loads the mesh and ensures the mesh has normals; it also optimizes the 
  324. // mesh for the graphics card's vertex cache, which improves performance by organizing 
  325. // the internal triangle list for less cache misses.
  326. //--------------------------------------------------------------------------------------
  327. HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh )
  328. {
  329.     ID3DXMesh* pMesh = NULL;
  330.     WCHAR str[MAX_PATH];
  331.     HRESULT hr;
  332.  
  333.     // Load the mesh with D3DX and get back a ID3DXMesh*.  For this
  334.     // sample we'll ignore the X file's embedded materials since we know 
  335.     // exactly the model we're loading.  See the mesh samples such as
  336.     // "OptimizedMesh" for a more generic mesh loading example.
  337.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, strFileName ) );
  338.     V_RETURN( D3DXLoadMeshFromX(str, D3DXMESH_MANAGED, pd3dDevice, NULL, NULL, NULL, NULL, &pMesh) );
  339.  
  340.     DWORD *rgdwAdjacency = NULL;
  341.  
  342.     // Make sure there are normals which are required for lighting
  343.     if( !(pMesh->GetFVF() & D3DFVF_NORMAL) )
  344.     {
  345.         ID3DXMesh* pTempMesh;
  346.         V( pMesh->CloneMeshFVF( pMesh->GetOptions(), 
  347.                                   pMesh->GetFVF() | D3DFVF_NORMAL, 
  348.                                   pd3dDevice, &pTempMesh ) );
  349.         V( D3DXComputeNormals( pTempMesh, NULL ) );
  350.  
  351.         SAFE_RELEASE( pMesh );
  352.         pMesh = pTempMesh;
  353.     }
  354.  
  355.     // Optimize the mesh for this graphics card's vertex cache 
  356.     // so when rendering the mesh's triangle list the vertices will 
  357.     // cache hit more often so it won't have to re-execute the vertex shader 
  358.     // on those vertices so it will improve perf.     
  359.     rgdwAdjacency = new DWORD[pMesh->GetNumFaces() * 3];
  360.     if( rgdwAdjacency == NULL )
  361.         return E_OUTOFMEMORY;
  362.     V( pMesh->ConvertPointRepsToAdjacency(NULL, rgdwAdjacency) );
  363.     V( pMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL) );
  364.     delete []rgdwAdjacency;
  365.  
  366.     *ppMesh = pMesh;
  367.  
  368.     return S_OK;
  369. }
  370.  
  371.  
  372. //--------------------------------------------------------------------------------------
  373. // This callback function will be called immediately after the Direct3D device has been 
  374. // reset, which will happen after a lost device scenario. This is the best location to 
  375. // create D3DPOOL_DEFAULT resources since these resources need to be reloaded whenever 
  376. // the device is lost. Resources created here should be released in the OnLostDevice 
  377. // callback. 
  378. //--------------------------------------------------------------------------------------
  379. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, 
  380.                                 const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  381. {
  382.     HRESULT hr;
  383.  
  384.     if( g_pFont )
  385.         V_RETURN( g_pFont->OnResetDevice() );
  386.     if( g_pEffect )
  387.         V_RETURN( g_pEffect->OnResetDevice() );
  388.  
  389.     // Create a sprite to help batch calls when drawing many lines of text
  390.     V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pSprite ) );
  391.  
  392.     for( int i=0; i<MAX_LIGHTS; i++ )
  393.         g_LightControl[i].OnResetDevice( pBackBufferSurfaceDesc  );
  394.  
  395.     // Setup the camera's projection parameters
  396.     float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height;
  397.     g_Camera.SetProjParams( D3DX_PI/4, fAspectRatio, 100.0f, 5000.0f );
  398.     g_Camera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
  399.     g_Camera.SetButtonMasks( MOUSE_LEFT_BUTTON, MOUSE_WHEEL, MOUSE_MIDDLE_BUTTON );
  400.  
  401.     g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 );
  402.     g_HUD.SetSize( 170, 170 );
  403.     g_SampleUI.SetLocation( pBackBufferSurfaceDesc->Width-170, pBackBufferSurfaceDesc->Height-300 );
  404.     g_SampleUI.SetSize( 170, 300 );
  405.  
  406.     return S_OK;
  407. }
  408.  
  409.  
  410. //--------------------------------------------------------------------------------------
  411. // This callback function will be called once at the beginning of every frame. This is the
  412. // best location for your application to handle updates to the scene, but is not 
  413. // intended to contain actual rendering calls, which should instead be placed in the 
  414. // OnFrameRender callback.  
  415. //--------------------------------------------------------------------------------------
  416. void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  417. {
  418.     // Update the camera's position based on user input 
  419.     g_Camera.FrameMove( fElapsedTime );
  420. }
  421.  
  422.  
  423. //--------------------------------------------------------------------------------------
  424. // This callback function will be called at the end of every frame to perform all the 
  425. // rendering calls for the scene, and it will also be called if the window needs to be 
  426. // repainted. After this function has returned, the sample framework will call 
  427. // IDirect3DDevice9::Present to display the contents of the next buffer in the swap chain
  428. //--------------------------------------------------------------------------------------
  429. void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  430. {
  431.     HRESULT hr;
  432.     D3DXMATRIXA16 mWorldViewProjection;
  433.     D3DXVECTOR3 vLightDir[MAX_LIGHTS];
  434.     D3DXCOLOR   vLightDiffuse[MAX_LIGHTS];
  435.     UINT iPass, cPasses;
  436.     D3DXMATRIXA16 mWorld;
  437.     D3DXMATRIXA16 mView;
  438.     D3DXMATRIXA16 mProj;
  439.    
  440.     // Clear the render target and the zbuffer 
  441.     V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DXCOLOR(0.0f,0.25f,0.25f,0.55f), 1.0f, 0) );
  442.  
  443.     // Render the scene
  444.     if( SUCCEEDED( pd3dDevice->BeginScene() ) )
  445.     {
  446.         // Get the projection & view matrix from the camera class
  447.         mWorld = g_mWorldFix * *g_Camera.GetWorldMatrix();
  448.         mProj = *g_Camera.GetProjMatrix();
  449.         mView = *g_Camera.GetViewMatrix();
  450.  
  451.         mWorldViewProjection = mWorld * mView * mProj;
  452.  
  453.         // Render the light spheres so the user can 
  454.         // visually see the light dir
  455.         for( int i=0; i<g_nNumActiveLights; i++ )
  456.         {
  457.             D3DXCOLOR arrowColor = ( i == g_nActiveLight ) ? D3DXCOLOR(1,1,0,1) : D3DXCOLOR(1,1,1,1);
  458.             V( g_LightControl[i].OnRender( arrowColor, &mView, &mProj, g_Camera.GetEyePt() ) );
  459.             vLightDir[i] = g_LightControl[i].GetLightDirection();
  460.             vLightDiffuse[i] = g_fLightScale * D3DXCOLOR(1,1,1,1);
  461.         }
  462.  
  463.         V( g_pEffect->SetValue( "g_LightDir", vLightDir, sizeof(D3DXVECTOR3)*MAX_LIGHTS ) );
  464.         V( g_pEffect->SetValue( "g_LightDiffuse", vLightDiffuse, sizeof(D3DXVECTOR4)*MAX_LIGHTS ) );
  465.  
  466.         // Update the effect's variables.  Instead of using strings, it would 
  467.         // be more efficient to cache a handle to the parameter by calling 
  468.         // ID3DXEffect::GetParameterByName
  469.         V( g_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProjection ) );
  470.         V( g_pEffect->SetMatrix( "g_mWorld", &mWorld ) );
  471.         V( g_pEffect->SetFloat( "g_fTime", (float)fTime ) );
  472.  
  473.         D3DXCOLOR vWhite = D3DXCOLOR(1,1,1,1);
  474.         V( g_pEffect->SetValue("g_MaterialDiffuseColor", &vWhite, sizeof(D3DXCOLOR) ) );
  475.         V( g_pEffect->SetFloat( "g_fTime", (float)fTime ) );      
  476.         V( g_pEffect->SetInt( "g_nNumLights", g_nNumActiveLights ) );      
  477.  
  478.         // Render the scene with this technique 
  479.         // as defined in the .fx file
  480.         switch( g_nNumActiveLights )
  481.         {
  482.             case 1: V( g_pEffect->SetTechnique( "RenderSceneWithTexture1Light" ) ); break;
  483.             case 2: V( g_pEffect->SetTechnique( "RenderSceneWithTexture2Light" ) ); break;
  484.             case 3: V( g_pEffect->SetTechnique( "RenderSceneWithTexture3Light" ) ); break;
  485.         }
  486.  
  487.  
  488.         // Apply the technique contained in the effect 
  489.         V( g_pEffect->Begin(&cPasses, 0) );
  490.  
  491.         for (iPass = 0; iPass < cPasses; iPass++)
  492.         {
  493.             V( g_pEffect->BeginPass(iPass) );
  494.  
  495.             // The effect interface queues up the changes and performs them 
  496.             // with the CommitChanges call. You do not need to call CommitChanges if 
  497.             // you are not setting any parameters between the BeginPass and EndPass.
  498.             // V( g_pEffect->CommitChanges() );
  499.  
  500.             // Render the mesh with the applied technique
  501.             V( g_pMesh->DrawSubset(0) );
  502.  
  503.             V( g_pEffect->EndPass() );
  504.         }
  505.         V( g_pEffect->End() );
  506.  
  507.         g_HUD.OnRender( fElapsedTime ); 
  508.         g_SampleUI.OnRender( fElapsedTime );
  509.  
  510.         RenderText( fTime );
  511.         
  512.         V( pd3dDevice->EndScene() );
  513.     }
  514. }
  515.  
  516.  
  517. //--------------------------------------------------------------------------------------
  518. // Render the help and statistics text. This function uses the ID3DXFont interface for 
  519. // efficient text rendering.
  520. //--------------------------------------------------------------------------------------
  521. void RenderText( double fTime )
  522. {
  523.     // The helper object simply helps keep track of text position, and color
  524.     // and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
  525.     // If NULL is passed in as the sprite object, then it will work fine however the 
  526.     // pFont->DrawText() will not be batched together.  Batching calls will improves perf.
  527.     CDXUTTextHelper txtHelper( g_pFont, g_pSprite, 15 );
  528.  
  529.     // Output statistics
  530.     txtHelper.Begin();
  531.     txtHelper.SetInsertionPos( 2, 0 );
  532.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
  533.     txtHelper.DrawTextLine( DXUTGetFrameStats() );
  534.     txtHelper.DrawTextLine( DXUTGetDeviceStats() );
  535.     
  536.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  537.     txtHelper.DrawFormattedTextLine( L"fTime: %0.1f  sin(fTime): %0.4f", fTime, sin(fTime) );
  538.     
  539.     // Draw help
  540.     if( g_bShowHelp )
  541.     {
  542.         const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
  543.         txtHelper.SetInsertionPos( 2, pd3dsdBackBuffer->Height-15*6 );
  544.         txtHelper.SetForegroundColor( D3DXCOLOR(1.0f, 0.75f, 0.0f, 1.0f ) );
  545.         txtHelper.DrawTextLine( L"Controls:" );
  546.  
  547.         txtHelper.SetInsertionPos( 20, pd3dsdBackBuffer->Height-15*5 );
  548.         txtHelper.DrawTextLine( L"Rotate model: Left mouse button\n"
  549.                                 L"Rotate light: Right mouse button\n"
  550.                                 L"Rotate camera: Middle mouse button\n"
  551.                                 L"Zoom camera: Mouse wheel scroll\n" );
  552.  
  553.         txtHelper.SetInsertionPos( 250, pd3dsdBackBuffer->Height-15*5 );
  554.         txtHelper.DrawTextLine( L"Hide help: F1\n" 
  555.                                 L"Quit: ESC\n" );
  556.     }
  557.     else
  558.     {
  559.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  560.         txtHelper.DrawTextLine( L"Press F1 for help" );
  561.     }
  562.     txtHelper.End();
  563. }
  564.  
  565.  
  566. //--------------------------------------------------------------------------------------
  567. // Before handling window messages, the sample framework passes incoming windows 
  568. // messages to the application through this callback function. If the application sets 
  569. // *pbNoFurtherProcessing to TRUE, then the sample framework will not process this message.
  570. //--------------------------------------------------------------------------------------
  571. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing )
  572. {
  573.     // Give the dialogs a chance to handle the message first
  574.     *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
  575.     if( *pbNoFurtherProcessing )
  576.         return 0;
  577.     *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
  578.     if( *pbNoFurtherProcessing )
  579.         return 0;
  580.  
  581.     g_LightControl[g_nActiveLight].HandleMessages( hWnd, uMsg, wParam, lParam );
  582.  
  583.     // Pass all remaining windows messages to camera so it can respond to user input
  584.     g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
  585.  
  586.     return 0;
  587. }
  588.  
  589.  
  590. //--------------------------------------------------------------------------------------
  591. // As a convenience, the sample framework inspects the incoming windows messages for
  592. // keystroke messages and decodes the message parameters to pass relevant keyboard
  593. // messages to the application.  The framework does not remove the underlying keystroke 
  594. // messages, which are still passed to the application's MsgProc callback.
  595. //--------------------------------------------------------------------------------------
  596. void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown )
  597. {
  598.     if( bKeyDown )
  599.     {
  600.         switch( nChar )
  601.         {
  602.             case VK_F1: g_bShowHelp = !g_bShowHelp; break;
  603.         }
  604.     }
  605. }
  606.  
  607.  
  608. //--------------------------------------------------------------------------------------
  609. // Handles the GUI events
  610. //--------------------------------------------------------------------------------------
  611. void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl )
  612. {
  613.     
  614.     switch( nControlID )
  615.     {
  616.         case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break;
  617.         case IDC_TOGGLEREF:        DXUTToggleREF(); break;
  618.         case IDC_CHANGEDEVICE:     DXUTSetShowSettingsDialog( !DXUTGetShowSettingsDialog() ); break;
  619.  
  620.         case IDC_ENABLE_PRESHADER: 
  621.         {
  622.             g_bEnablePreshader = g_SampleUI.GetCheckBox( IDC_ENABLE_PRESHADER )->GetChecked(); 
  623.  
  624.             if( DXUTGetD3DDevice() != NULL )
  625.             {
  626.                 OnLostDevice();
  627.                 OnDestroyDevice();
  628.                 OnCreateDevice( DXUTGetD3DDevice(), DXUTGetBackBufferSurfaceDesc() );
  629.                 OnResetDevice( DXUTGetD3DDevice(), DXUTGetBackBufferSurfaceDesc() );
  630.             }
  631.             break;
  632.         }
  633.  
  634.         case IDC_ACTIVE_LIGHT:
  635.             if( !g_LightControl[g_nActiveLight].IsBeingDragged() )
  636.             {
  637.                 g_nActiveLight++;
  638.                 g_nActiveLight %= g_nNumActiveLights;
  639.             }
  640.             break;
  641.  
  642.         case IDC_NUM_LIGHTS:
  643.             if( !g_LightControl[g_nActiveLight].IsBeingDragged() )
  644.             {
  645.                 WCHAR sz[100];
  646.                 _snwprintf( sz, 100, L"# Lights: %d", g_SampleUI.GetSlider( IDC_NUM_LIGHTS )->GetValue() ); sz[99] = 0;
  647.                 g_SampleUI.GetStatic( IDC_NUM_LIGHTS_STATIC )->SetText( sz );
  648.  
  649.                 g_nNumActiveLights = g_SampleUI.GetSlider( IDC_NUM_LIGHTS )->GetValue();
  650.                 g_nActiveLight %= g_nNumActiveLights;
  651.             }
  652.             break;
  653.  
  654.         case IDC_LIGHT_SCALE: 
  655.             g_fLightScale = (float) (g_SampleUI.GetSlider( IDC_LIGHT_SCALE )->GetValue() * 0.10f);
  656.  
  657.             WCHAR sz[100];
  658.             _snwprintf( sz, 100, L"Light scale: %0.2f", g_fLightScale ); sz[99] = 0;
  659.             g_SampleUI.GetStatic( IDC_LIGHT_SCALE_STATIC )->SetText( sz );
  660.             break;
  661.     }
  662.     
  663. }
  664.  
  665.  
  666. //--------------------------------------------------------------------------------------
  667. // This callback function will be called immediately after the Direct3D device has 
  668. // entered a lost state and before IDirect3DDevice9::Reset is called. Resources created
  669. // in the OnResetDevice callback should be released here, which generally includes all 
  670. // D3DPOOL_DEFAULT resources. See the "Lost Devices" section of the documentation for 
  671. // information about lost devices.
  672. //--------------------------------------------------------------------------------------
  673. void CALLBACK OnLostDevice()
  674. {
  675.     CDXUTDirectionWidget::StaticOnLostDevice();
  676.     if( g_pFont )
  677.         g_pFont->OnLostDevice();
  678.     if( g_pEffect )
  679.         g_pEffect->OnLostDevice();
  680.     SAFE_RELEASE(g_pSprite);
  681.     
  682. }
  683.  
  684.  
  685. //--------------------------------------------------------------------------------------
  686. // This callback function will be called immediately after the Direct3D device has 
  687. // been destroyed, which generally happens as a result of application termination or 
  688. // windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  689. // should be released here, which generally includes all D3DPOOL_MANAGED resources. 
  690. //--------------------------------------------------------------------------------------
  691. void CALLBACK OnDestroyDevice()
  692. {
  693.     CDXUTDirectionWidget::StaticOnDestroyDevice();
  694.     SAFE_RELEASE(g_pEffect);
  695.     SAFE_RELEASE(g_pFont);
  696.     SAFE_RELEASE(g_pMesh);
  697.     SAFE_RELEASE(g_pMeshTexture);
  698.     SAFE_RELEASE(g_pArrowMesh);
  699. }
  700.  
  701.  
  702.  
  703.